package com.runjian.rundo.iot.agent.iec104.parser.frame;

import java.util.List;

import cn.hutool.core.util.ArrayUtil;
import com.runjian.rundo.iot.agent.iec104.consts.Action;

import cn.hutool.core.util.ByteUtil;
import cn.hutool.core.util.StrUtil;
import io.netty.buffer.ByteBuf;
import lombok.Getter;
import lombok.Setter;
import lombok.experimental.SuperBuilder;

/**
 * I格式 帧
 *
 * @author CaoQingHua
 */
@Getter
@Setter
@SuperBuilder
public class IIec104Frame extends AIec104Frame {

    /**
     * 发送序列号
     */
    private short sendNo;
    /**
     * 接收序列号
     */
    private short receiveNo;

    /**
     * I侦内容体
     */
    private ASDUFrame asdu;

    @Override
    public AIec104Frame replyFrame() {
        // 回复时,接收序号与回复序号不由侦本身决定,由deviceSession决定
        ASDUFrame asdu = this.asdu.replyFrame();
        if (asdu == null) {
            return null;
        }
        this.asdu = asdu;
        return this;
    }

    @Override
    public ByteBuf assemblyByteBuf() {
        ByteBuf assembleByteBuf = super.assemblyByteBuf();
        //获取类型
        assembleByteBuf.writeByte((byte)this.asdu.getTi().getCode());
        // 组装可变结构限定词(vsq) 1字节, 第一位(sq):0.地址不连续,1.地址连续, 后七位:
        // 应用服务数据单元信息元素(单个信息元素或同类信息元素组合)的数目<0>∶＝应用服务数据单元不含信息对象;<1..127>∶＝应用服务数据单元信息元素的数目
        byte vsq = 0;
        if (this.asdu.getSq()) {
            // 设置第一位: 1000 0000
            vsq |= (byte)0x80;
        }
        // 先将前缀头带过去，
        vsq |= (byte)(this.asdu.getInfoElements().size() & 0x7F);
        assembleByteBuf.writeByte(vsq);
        // ************** 组装可变结构限定词(cot) *************************
        byte cot = 0;
        if (this.asdu.getT()) {
            // 设置第一位: 1000 0000
            cot |= (byte)0x80;
        }
        if (this.asdu.getPN()) {
            // 设置第二位: 0100 0000
            cot |= 0x40;
        }
        // 设置原因
        cot |= (byte)(this.asdu.getCot().getCode() & 0x3F);
        assembleByteBuf.writeByte(cot);
        // 默认写死的0 Originator address 它为控制站提供了一种明确标识自身的方式 如果未使用源发站地址（位设置为零）
        assembleByteBuf.writeByte((byte)0);
        // ************** 应用服务数据单元公共地址 *************************
        assembleByteBuf.writeBytes(ByteUtil.shortToBytes(this.asdu.getAddress()));
        // ************** 组装数据 *************************
        this.asdu.getInfoElements().forEach(infoElement -> {
            byte[] bytes = ByteUtil.intToBytes(infoElement.getAddress());
            // 组装信息对象地址,三个字节
//            assembleByteBuf.writeBytes(new byte[] {(byte)((infoElement.getAddress() >> 16) & 0xFF),
//                (byte)((infoElement.getAddress() >> 8) & 0xFF), (byte)(infoElement.getAddress() & 0xFF)});
            assembleByteBuf.writeBytes(ArrayUtil.sub(bytes,0,3));
            // 拼装数据元素字节
            this.asdu.writeInfoContent(assembleByteBuf, infoElement);
            if (null != infoElement.getQds()) {
                // 组装信息元素限定词
                assembleByteBuf.writeByte((byte)(infoElement.getQds() & 0xFF));
            }
            if (null != infoElement.getDate()) {
                // 写入时标
                assembleByteBuf.writeBytes(((Cp56Time2a)infoElement.getDate()).toBytes());
            }
        });
        // ************** 组装qos或者qoi *************************
        if (null != this.asdu.getQos()) {
            assembleByteBuf.writeByte((byte)(this.asdu.getQos() & 0xFF));
        }
        return assembleByteBuf;
    }

    /**
     * 下一步要执行的动作
     * 
     * @return 回复动作
     */
    @Override
    public List<Action> action() {
        return this.asdu.action();
    }

    @Override
    public String console() {
        return StrUtil.format("\nI帧 发送序列号:{}  接收序列号:{}\n---------------------------------------------\n{}", sendNo, receiveNo,
            asdu.console());
    }

}
